package co.gov.medellin.sdep.sisdep.security.sap.portal;

import java.io.Serializable;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;

import javax.faces.application.FacesMessage;
import javax.faces.application.FacesMessage.Severity;
import javax.faces.context.FacesContext;

import co.gov.medellin.sdep.sisdep.domain.FacesController;

import com.sap.security.api.IGroup;
import com.sap.security.api.IGroupFactory;
import com.sap.security.api.ISearchResult;
import com.sap.security.api.IUser;
import com.sap.security.api.IUserFactory;
import com.sap.security.api.IUserSearchFilter;
import com.sap.security.api.UMException;
import com.sap.security.api.UMFactory;

/**
 * Clase que define la funcionalidad para la gestion los grupos de usuarios y la validacion
 * de permisos asociados con esto.
 * 
 * @author carlos.perez@consult-soft.com
 * @version 03-07-2012 
 */
public class UserPermissionManagerController implements Serializable {
	
	private static final long serialVersionUID = -6714576438376742742L;
	
	private String userName;
	private String userId; 
	private String userIdValidate;
	private String userAddress;
	private String userTelephone;
	private String userEmail;

	private List userGroupsManagerList;	
			
	private UserGroupVO userGroupTbl;
	
	private boolean transactionOk;
	private boolean doConsultUserSAP;
			
	
	/** Prefijo usado en el ID de usuario al autenticarse en el Portal SAP */
	private final static String USER_PREFIX_ID_SAP = "S";
	
	/** Grupos de usuarios definidos para la aplicacion SISDEP, creados por el administrador del Portal SAP
	 * basado en el formato entregado como la matriz de Roles y Responsabilidades (XLS) */
	private final static String ADMON_GROUP   = "admon.sisdepweb";
	private final static String GESTION_GROUP = "gestion.sisdepweb";
	private final static String REGULACION_GROUP = "regulacion.sisdepweb"; 
	public final static String OPERATIVA_GROUP   = "operativa.sisdepweb";
	public final static String PEV_GROUP = "publi_ext_visual.sisdepweb";
	public final static String CENTROS_COM_GROUP = "centros_comerc.sisdepweb";
	public final static String INFORMES_GROUP    = "consultas_informes.sisdepweb";
	
	private boolean admonPermission;
	private boolean gestionPermission;
	private boolean regulacionPermission;
	private boolean operativaPermission;
	private boolean pevPermission;
	private boolean centroComPermission;
	private boolean informesPermission;

	/**
	 * Constructor para establebler los valores iniciales de la gestion de grupos.
	 * 
	 * @author carlos.perez@consult-soft.com
	 * @version 05-07-2012 
 	 *
	 */
	public UserPermissionManagerController(){
		initializationProperties();
		initializationComponents();		
	}
	
	/**
	 * Metodo que realiza la inicializacion de las propiedades basicas para la gestion de
	 * grupos y los usuarios relacionados.
	 * 
	 * @author carlos.perez@consult-soft.com
	 * @version 05-07-2012 
 	 *
	 */
	private void initializationProperties(){
		userId = "";
		userName = "";
		userAddress = "";
		userTelephone = "";
		userEmail = "";
		userIdValidate = "";
		doConsultUserSAP = false;
		transactionOk = false;
	}
	
	/**
	 * Metodo donde se inicializan los Objetos usandos en el manejo de la administracion de los grupos de usuario.
	 * 
	 * @author carlos.perez@consult-soft.com
	 * @version 05-07-2012 
	 *
	 */
	private void initializationComponents() {
		userId = FacesController.getLoggedUserID();		
		loadAllGroup();
		if(userId != null) {
			validarUsuarioSAP();
		}
	}	
		
	/**
	 * Metodo que permite obtener el listado de Grupos de usuarios implementados para la autorizacion
	 * a nivel de grupos (permisos) dentro de la aplicacion SISDEP en el portal del ciudadano.
	 * 
	 * @author carlos.perez@consult-soft.com
	 * @version 05-07-2012 
	 *
	 */
	private void loadAllGroup() {
		userGroupsManagerList = detailLoadAllGroup();
		if (userGroupsManagerList == null || userGroupsManagerList.isEmpty()) {
			addFacesMessage("messagesPanel", "Los grupos de usuarios NO han sido configurados.", true);
			return;
		}
	}		

	/**
	 * Metodo encargado de agregar la lista de grupos PRE-configurados en el portal para la seguridad de la aplicacion SISDEP.
	 * 
	 * @author carlos.perez@consult-soft.com
	 * @version 05-07-2012 
	 *
	 */
	private List detailLoadAllGroup(){
		UserGroupVO temp = new UserGroupVO();
		
		ArrayList searchResults = new ArrayList(7);
		temp.setGroupEspecification("Grupo de Administradores");
		temp.setGroupConfigurationSAP(ADMON_GROUP);
		temp.setGroupDescription("Usuario Administrador");
		searchResults.add(temp);
			
		temp = new UserGroupVO();
		temp.setGroupEspecification("GRUPOS GESTION");
		temp.setGroupConfigurationSAP(GESTION_GROUP);
		temp.setGroupDescription("Usuarios de GESTION");
		searchResults.add(temp);
			
		temp = new UserGroupVO();
		temp.setGroupEspecification("GRUPO REGULACION");
		temp.setGroupConfigurationSAP(REGULACION_GROUP);
		temp.setGroupDescription("Usuarios de REGULACION");
		searchResults.add(temp);
			
		temp = new UserGroupVO();
		temp.setGroupEspecification("GRUPO OPERATIVA");
		temp.setGroupConfigurationSAP(OPERATIVA_GROUP);
		temp.setGroupDescription("Usuarios de OPERATIVA");
		searchResults.add(temp);

		temp = new UserGroupVO();
		temp.setGroupEspecification("GRUPO PEV");
		temp.setGroupConfigurationSAP(PEV_GROUP);
		temp.setGroupDescription("Usuarios de PEV");
		searchResults.add(temp);

		temp = new UserGroupVO();
		temp.setGroupEspecification("GRUPO CENTROS COMERCIALES");
		temp.setGroupConfigurationSAP(CENTROS_COM_GROUP);
		temp.setGroupDescription("Usuarios de CENTROS COMERCIALES");
		searchResults.add(temp);

		temp = new UserGroupVO();
		temp.setGroupEspecification("GRUPO DE INFORMES");
		temp.setGroupConfigurationSAP(INFORMES_GROUP);
		temp.setGroupDescription("Usuarios de COSULTAS E INFORMES");
		searchResults.add(temp);

		return (List)searchResults;
	}		
		
	/**
	 * Metodo que permite especificar los mensajes de validacion producidos por la aplicacion
	 * hacia el usuario en el procesamiento de operaciones de gestion de grupos de usuarios.
	 * 
	 * @param contexForMessage
	 * @param message
	 * @param errorCurrent 
	 * 
	 * @author carlos.perez@consult-soft.com
	 * @version 05-07-2012 
	 * 
	 */
	private void addFacesMessage(String contexForMessage, String message, boolean errorCurrent) {
		if (contexForMessage == null || contexForMessage.equals("null") || contexForMessage.equals("")) {
			contexForMessage = "messagesPanel"; //contexto para mensajes generales
		}
	
		if (errorCurrent) {
			Severity severity = FacesMessage.SEVERITY_ERROR;
			FacesContext context = FacesContext.getCurrentInstance();
			context.addMessage(contexForMessage, new FacesMessage(severity, " Error : " + message, ""));
			transactionOk = false;
		} else {
			Severity severity = FacesMessage.SEVERITY_INFO;
			FacesContext context = FacesContext.getCurrentInstance();
			context.addMessage(contexForMessage, new FacesMessage(severity, " Procesada con \u00E9xito : " + message, ""));
			transactionOk = true;
		}
	}
			
	/**
	 * Metodo que permite verificar que un usuario este registrado en el portal de ciudadano
	 * por medio de su identificacion.
	 * 
	 * @author carlos.perez@consult-soft.com
	 * @version 05-07-2012 
	 *  
	 */
	public void validarUsuarioSAP() {
		doConsultUserSAP=false;
		if (userId==null || userId.equals("")){
			addFacesMessage("messagesPanel", "El campo usuario es obligatorio.", true);
			return;
		}else{
			try{
				getNameFromId(USER_PREFIX_ID_SAP + userId);	
				if (userIdValidate != null && !userIdValidate.equals("")){
					findUserGroups(userIdValidate);
				}
			}catch(Exception e){
				System.err.println("UserPermissionManagerController::validarUsuarioSAP-->ocurrio un error en la verificacion del usuario: " + userIdValidate);
				e.printStackTrace(System.err);	
			}
		}
	}
		
	/**
	 * Metodo que asiganar el usuario especificado a un grupo, usa como parametros
	 * el nombre del grupo y usuario.
	 * 
	 * @author carlos.perez@consult-soft.com
	 * @version 05-07-2012 
	 *  
	 */
	public void grantGroup(){
		if (userIdValidate==null || userIdValidate.equals("") || !doConsultUserSAP){
			addFacesMessage("messagesPanel", "Operaci\u00F3n cancelada, los datos del usuario deben ser validados.", true);
			return;
		}else{
			try{
				Map param = FacesContext.getCurrentInstance().getExternalContext().getRequestParameterMap();
				userGroupTbl = (UserGroupVO) getUserGroupsManagerList().get(Integer.parseInt((String) param.get("index")));
				if (userGroupTbl != null){
					if (setUserGroup(userIdValidate,userGroupTbl.getGroupConfigurationSAP(),1) == 0){
						addFacesMessage("messagesPanel", "Actualizaci\u00F3n realizada con \u00E9xito.", false);
						userGroupTbl.setGroupEnabled(true);
						optionDisabledMenu(userGroupTbl.getGroupConfigurationSAP(), true);	
					}else{
						addFacesMessage("messagesPanel", "Fall\u00F3 la asignaci\u00F3n del usuario al grupo "+userGroupTbl.getGroupEspecification(), true);
					}
				}					
			}catch(Exception e){
				addFacesMessage("messagesPanel", "Fall\u00F3 la asignaci\u00F3n del usuario al grupo "+userGroupTbl.getGroupConfigurationSAP().trim(), true);
			}
		}
	}
				
	/**
	 * Metodo que permite excluir el usuario especificado del grupo seleccionado, recibe como parametros
	 * el nombre del grupo y usuario
	 * 
	 * @author carlos.perez@consult-soft.com
	 * @version 05-07-2012 
	 *  
	 */
	public void excludeGroup(){
		if (userIdValidate==null || userIdValidate.equals("")){
			addFacesMessage("messagesPanel", "El campo usuario es obligatorio.", true);
			return;
		}else{
			try{
				Map param = FacesContext.getCurrentInstance().getExternalContext().getRequestParameterMap();
				userGroupTbl = (UserGroupVO) getUserGroupsManagerList().get(Integer.parseInt((String) param.get("index")));
				if (userGroupTbl != null){
					if (setUserGroup(userIdValidate,userGroupTbl.getGroupConfigurationSAP(),0) == 0){
						addFacesMessage("messagesPanel", "usuario Excluido con \u00E9xito.", false);
						userGroupTbl.setGroupEnabled(false);
						optionDisabledMenu(userGroupTbl.getGroupConfigurationSAP(), false);
					}else{
						addFacesMessage("messagesPanel", "Fall\u00F3 el proceso de Exclusi\u00F3n del grupo "+userGroupTbl.getGroupEspecification(), true);
					}
				}
			}catch(Exception e){
				addFacesMessage("messagesPanel", "Fall\u00F3 la exlusi\u00F3n del usuario al grupo.", true);
				System.err.println("UserPermissionManagerController::excludeGroup-->ocurrio un error en la exclusion del usuario a Grupos: ");
				e.printStackTrace(System.err);	
			}
		}
	}	
		
	/**
	 * Metodo encargado de deshabilitar o habilitar las opciones del menu principal, recibe como parametro el nombre del grupo
	 * Se actualizan las opciones de permisos del menu solo para el usuario autenticado (LoggedUserID).
	 * En otro caso NO, pues el atributo "userId" contiene una identificacion de alguien NO autenticado
	 * actualmente. Para presentar el menu del otro usuario se debe ingresar a la aplicacion nuevamente.
	 * 
	 * @author carlos.perez@consult-soft.com
	 * @version 05-07-2012 
	 *  
	 */
	private void optionDisabledMenu(String nameOption, boolean disabled) {
		if(this.userId.equals(FacesController.getLoggedUserID())) {
			if (nameOption.equals(ADMON_GROUP)){
				admonPermission = disabled;
			} else if(nameOption.equals(GESTION_GROUP)){
				gestionPermission = disabled;
			} else if(nameOption.equals(REGULACION_GROUP)){
				regulacionPermission = disabled;
			} else if(nameOption.equals(OPERATIVA_GROUP)){
				operativaPermission = disabled;
			} else if(nameOption.equals(PEV_GROUP)){
				pevPermission = disabled;
			} else if(nameOption.equals(CENTROS_COM_GROUP)){
				centroComPermission = disabled;
			} else if(nameOption.equals(INFORMES_GROUP)){
				informesPermission = disabled;
			}
		}
	}
		
	/**
	 * Metodo que permite la asignacion y exclusion de los usuarios a Grupos del portal
	 * 
	 * El parametro opereacion define:
	 * 1-- Se agrega el usuario al grupo
	 * 0-- Se excluye el usuario del grupo
	 * 
	 * @author carlos.perez@consult-soft.com
	 * @version 05-07-2012 
	 *   
	 */
	private int setUserGroup(String id_usuario, String nombre_grupo, int operation)
	{	
		int flag = 0;
		if(false) {
		IGroupFactory groupFactory = UMFactory.getGroupFactory();
		try
		{
			String uniqueIDGrupo = groupFactory.getGroupByUniqueName(nombre_grupo).getUniqueID();
			String uniqueID = UMFactory.getUserFactory().getUserByLogonID(id_usuario).getUniqueID();
			if (operation==1){
				groupFactory.addUserToGroup(uniqueID, uniqueIDGrupo);
			}else{
				groupFactory.removeUserFromGroup(uniqueID,uniqueIDGrupo);	
			}
		}
		catch(Exception e) {
			flag = -1;
			System.err.println("UserPermissionManagerController::setUserGroup-->Error asignando usuario al grupo: " + id_usuario  + "--" + nombre_grupo);
			e.printStackTrace(System.err);
		}
		}
		return flag;
	}
			
		
	/*Listado de Grupos del usuario validado*/
	/**
	 * Metodo que permite obtener el listado actual de los grupos a los cuales esta asociado el usuario
	 * especificado.
	 * 
	 * @author carlos.perez@consult-soft.com
	 * @version 05-07-2012 
	 *   
	 */
	private Map getUserGroup(String id_usuario){
		Map userGroupUME = new HashMap();
		userGroupUME.put(ADMON_GROUP,"ADMON");
		userGroupUME.put(GESTION_GROUP,"GESTION");
		userGroupUME.put(REGULACION_GROUP,"REGULACION");
		userGroupUME.put(OPERATIVA_GROUP,"OPERATIVA");
		userGroupUME.put(PEV_GROUP,"PEV");
		userGroupUME.put(CENTROS_COM_GROUP,"CENTROS COM");
		userGroupUME.put(INFORMES_GROUP,"INFORMES");
//		check point ...
		if(false) {
		try
		{
			IUserFactory ufactory = UMFactory.getUserFactory();
			IGroupFactory rfcat = UMFactory.getGroupFactory();
			IUser myuser = ufactory.getUserByLogonID(id_usuario);
			Iterator i = myuser.getParentGroups(true);
			IGroup ugroup = null; 
			userGroupUME = new HashMap();
			while(i.hasNext())
			{
				String s=(String)i.next();
				ugroup=rfcat.getGroup(s);
				if (userGroupUME.get(ugroup.getDisplayName().trim()) == null){
					userGroupUME.put(ugroup.getDisplayName().trim(),ugroup.getDisplayName().trim());
				}				
			}
		}catch(UMException e)
		{
			System.err.println("UserPermissionManagerController::getUserGroup-->Error consultando los GRUPOS del usuario: " + id_usuario);
			e.printStackTrace(System.err);
		}
		}
		return userGroupUME;		
	}
		
	/**
	 * Metodo que consulata los grupos que tiene asiganado el usuario autenticado
	 * actulmente en el sistema, e inicializa los permisos asociados por grupo.
	 * 
	 * @author carlos.perez@consult-soft.com
	 * @version 05-07-2012 
	 *   
	 */
	private void findUserGroups(String pUserId) {
		if (userGroupsManagerList != null && !userGroupsManagerList.isEmpty()) {
			try{
				Map pGroup = getUserGroup(pUserId);
				if (pGroup != null && !pGroup.isEmpty()){
					Iterator iterResultado = userGroupsManagerList.iterator();
					UserGroupVO userGroup = null;
					while (iterResultado.hasNext()){
						userGroup = (UserGroupVO)iterResultado.next();
						if (pGroup.get(userGroup.getGroupConfigurationSAP().trim()) != null){
							userGroup.setGroupEnabled(true);
						}else{
							userGroup.setGroupEnabled(false);				
						}
						optionDisabledMenu(userGroup.getGroupConfigurationSAP(),userGroup.isGroupEnabled());
					}
				}
			}catch(Exception e){
				System.err.println("UserPermissionManagerController::locateGroup-->Error inicialzando los GRUPOS del usuario: " + userIdValidate);
				e.printStackTrace(System.err);
			}
		}
	}		
			
	/** 
	 * Obtiene los datos basicos del usuario registrado en la UME (Portal SAP).
	 * 
	 * @author carlos.perez@consult-soft.com
	 * @version 05-07-2012 
	 *    
	 */
	private void getNameFromId(String id) throws UMException {
		doConsultUserSAP=true;
		userName="Carlos Perez Moncada";
		userTelephone="4567845";
		userAddress="Calle 45B nro 70a-45";
		userEmail="carlos.perez@medellin.gov.co";
			
		userIdValidate=id;
		if(false) {
//			check point ...
			IUserFactory userFactory = UMFactory.getUserFactory();
			IUserSearchFilter filter = null;
			ISearchResult result = null;
			
			try
			{
				filter = userFactory.getUserSearchFilter();
				filter.setUniqueName(id, 0, true);
				result = userFactory.searchUsers(filter);
			}
			catch(UMException e)
			{
				throw e;
			}
			
			if(result != null && result.hasNext()){
				String uniqeID = result.next().toString();
				IUser user = UMFactory.getUserFactory().getUser(uniqeID);
				doConsultUserSAP=true;
				if (user.getLastName() != null && !"".equals(user.getLastName())){
					userName=user.getFirstName() + " " + user.getLastName();
				}else{
					userName=user.getFirstName();
				}
				userTelephone=user.getTelephone();
				userAddress=user.getStreet();
				userEmail=user.getEmail();
					
				userIdValidate=id;
					
				/*verificamos los grupos asignados*/
				getUserGroup((String)id); 
			}else{
				userIdValidate="";
				addFacesMessage("messagesPanel", "El usuario NO ha sido registrado en el Portal del Ciudadano.", true);
				return;
			}
		}
	}
		
	/**
	 * Metodo que recibe como parametro el usuario autenticado en la Ume y retorna
	 * como resultado el nombre del Usuario. 
	 * 
	 * @author carlos.perez@consult-soft.com
	 * @version 05-07-2012 
	 *     
	 */
	public String getUserNameFromId(String id) throws UMException{
		
		IUserFactory userFactory = UMFactory.getUserFactory();
		IUserSearchFilter filter = null;
		ISearchResult result = null;
		String valueReturn="";
		try
		{
			filter = userFactory.getUserSearchFilter();
			filter.setUniqueName(id, 0, true);
			result = userFactory.searchUsers(filter);
		}
		catch(UMException e)
		{
			throw e;
		}
		
		if(result != null && result.hasNext()){
			String uniqeID = result.next().toString();
			IUser user = UMFactory.getUserFactory().getUser(uniqeID);
			if (user.getLastName() != null && !"".equals(user.getLastName())){
				valueReturn=user.getFirstName() + " " + user.getLastName();
			}else{
				valueReturn=user.getFirstName();
			}
		}
		return valueReturn;
	}
		
	/**
	 * @return
	 */
	public boolean isDoConsultUserSAP() {
		return doConsultUserSAP;
	}

	/**
	 * @return
	 */
	public boolean isTransactionOk() {
		return transactionOk;
	}

	/**
	 * @return
	 */
	public String getUserAddress() {
		return userAddress;
	}

	/**
	 * @return
	 */
	public String getUserEmail() {
		return userEmail;
	}

	/**
	 * @return
	 */
	public List getUserGroupsManagerList() {
		return userGroupsManagerList;
	}

	/**
	 * @return
	 */
	public UserGroupVO getUserGroupTbl() {
		return userGroupTbl;
	}

	/**
	 * @return
	 */
	public String getUserId() {
		return userId;
	}

	/**
	 * @return
	 */
	public String getUserIdValidate() {
		return userIdValidate;
	}

	/**
	 * @return
	 */
	public String getUserName() {
		return userName;
	}

	/**
	 * @return
	 */
	public String getUserTelephone() {
		return userTelephone;
	}

	/**
	 * @param b
	 */
	public void setDoConsultUserSAP(boolean b) {
		doConsultUserSAP = b;
	}

	/**
	 * @param b
	 */
	public void setTransactionOk(boolean b) {
		transactionOk = b;
	}

	/**
	 * @param string
	 */
	public void setUserAddress(String string) {
		userAddress = string;
	}

	/**
	 * @param string
	 */
	public void setUserEmail(String string) {
		userEmail = string;
	}

	/**
	 * @param list
	 */
	public void setUserGroupsManagerList(List list) {
		userGroupsManagerList = list;
	}

	/**
	 * @param tbl
	 */
	public void setUserGroupTbl(UserGroupVO tbl) {
		userGroupTbl = tbl;
	}

	/**
	 * @param string
	 */
	public void setUserId(String string) {
		userId = string;
	}

	/**
	 * @param string
	 */
	public void setUserIdValidate(String string) {
		userIdValidate = string;
	}

	/**
	 * @param string
	 */
	public void setUserName(String string) {
		userName = string;
	}

	/**
	 * @param string
	 */
	public void setUserTelephone(String string) {
		userTelephone = string;
	}

	/**
	 * @return the admonPermission
	 */
	public boolean isAdmonPermission() {
		return admonPermission;
	}

	/**
	 * @param admonPermission the admonPermission to set
	 */
	public void setAdmonPermission(boolean admonPermission) {
		this.admonPermission = admonPermission;
	}

	/**
	 * @return the gestionPermission
	 */
	public boolean isGestionPermission() {
		return gestionPermission;
	}

	/**
	 * @param gestionPermission the gestionPermission to set
	 */
	public void setGestionPermission(boolean gestionPermission) {
		this.gestionPermission = gestionPermission;
	}

	/**
	 * @return the regulacionPermission
	 */
	public boolean isRegulacionPermission() {
		return regulacionPermission;
	}

	/**
	 * @param regulacionPermission the regulacionPermission to set
	 */
	public void setRegulacionPermission(boolean regulacionPermission) {
		this.regulacionPermission = regulacionPermission;
	}

	/**
	 * @return the operativaPermission
	 */
	public boolean isOperativaPermission() {
		return operativaPermission;
	}

	/**
	 * @param operativaPermission the operativaPermission to set
	 */
	public void setOperativaPermission(boolean operativaPermission) {
		this.operativaPermission = operativaPermission;
	}

	/**
	 * @return the pevPermission
	 */
	public boolean isPevPermission() {
		return pevPermission;
	}

	/**
	 * @param pevPermission the pevPermission to set
	 */
	public void setPevPermission(boolean pevPermission) {
		this.pevPermission = pevPermission;
	}

	/**
	 * @return the centroComPermission
	 */
	public boolean isCentroComPermission() {
		return centroComPermission;
	}

	/**
	 * @param centroComPermission the centroComPermission to set
	 */
	public void setCentroComPermission(boolean centroComPermission) {
		this.centroComPermission = centroComPermission;
	}

	/**
	 * @return the informesPermission
	 */
	public boolean isInformesPermission() {
		return informesPermission;
	}

	/**
	 * @param informesPermission the informesPermission to set
	 */
	public void setInformesPermission(boolean informesPermission) {
		this.informesPermission = informesPermission;
	}
}
